package com.example.dev_demo.excel.imports;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.DefaultIndexedColorMap;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.List;

/**
 * 修正后的错误批注添加工具类
 */
@Slf4j
public class ExcelErrorCommentUtil {

    /**
     * 给错误单元格添加批注和样式，并输出到响应流
     *
     * @param file     原始上传文件
     * @param errors   错误列表
     * @param response 响应对象
     */
    public static void addErrorComments(HttpServletResponse response, MultipartFile file, List<ExcelImportUtil.ImportError> errors,
                                        int headerRowNum, String fileName) throws IOException {
        try (InputStream is = file.getInputStream();
             Workbook workbook = WorkbookFactory.create(is); // 读取原始Excel
             OutputStream os = response.getOutputStream()) {

            // 获取第一个工作表（默认处理第一个sheet）
            Sheet sheet = workbook.getSheetAt(0);
            if (sheet == null) {
                throw new RuntimeException("Excel中无工作表");
            }

            // 获取表头行（默认第0行）
            Row headerRow = sheet.getRow(headerRowNum);
            if (headerRow == null) {
                throw new RuntimeException("Excel中无表头行");
            }

            // 创建批注所需的绘图对象（每个sheet一个）
            Drawing<?> drawing = sheet.createDrawingPatriarch();

            // 创建错误单元格样式（背景色浅红）
            CellStyle errorStyle = createErrorCellStyle(workbook);

            // 遍历错误列表，添加批注和样式
            for (ExcelImportUtil.ImportError error : errors) {
                try {
                    int userRowNum = error.getRowNum(); // 用户可见行号（从1开始）
                    String headerName = error.getFieldName(); // 表头名（如“用户名”）
                    String errorMsg = error.getErrorMsg();

                    // 1. 转换行索引：用户行号-1（POI行索引从0开始）
                    int poiRowNum = userRowNum - 1;
                    Row row = sheet.getRow(poiRowNum);
                    if (row == null) {
                        // 若行为空，创建行（避免空指针）
                        row = sheet.createRow(poiRowNum);
                    }

                    // 2. 获取列索引（根据表头名找对应列）
                    int columnIndex = getColumnIndexByHeader(headerRow, headerName);
                    if (columnIndex == -1) {
                        // 列索引无效，跳过（可记录日志）
                        continue;
                    }

                    // 3. 获取或创建单元格
                    Cell cell = row.getCell(columnIndex);
                    if (cell == null) {
                        cell = row.createCell(columnIndex);
                    }

                    // 4. 设置错误单元格样式（背景色）
                    cell.setCellStyle(errorStyle);

                    // 5. 创建批注
                    // 创建批注位置锚点（默认在单元格右下方显示）
                    ClientAnchor anchor = workbook.getCreationHelper().createClientAnchor();
                    anchor.setRow1(poiRowNum); // 批注起始行
                    anchor.setCol1(columnIndex + 1); // 批注起始列（当前列右侧）

                    // 创建批注对象
                    Comment comment = drawing.createCellComment(anchor);
                    // 设置批注内容（支持多行）
                    RichTextString richText = workbook.getCreationHelper().createRichTextString(errorMsg);
                    comment.setString(richText);
                    // 设置批注作者（可选）
                    comment.setAuthor("系统校验");

                    // 将批注绑定到单元格
                    cell.setCellComment(comment);
                } catch (Exception ex) {
                    log.error("ERROR:", ex);
                }
            }

            // 6. 输出Excel到响应流
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            String exportFileName = URLEncoder.encode("系统校验_" + fileName + "_" + System.currentTimeMillis() + ".xlsx", "UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + exportFileName);
            workbook.write(os);
            os.flush();
        }
    }

    /**
     * 创建错误单元格样式（浅红色背景）
     */
    private static CellStyle createErrorCellStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        // 设置背景色（浅红）
        // 注意：HSSF（xls）和XSSF（xlsx）的颜色索引不同，这里兼容处理
        if (workbook instanceof XSSFWorkbook) {
            // XSSF（xlsx）使用IndexedColors.RED.getIndex()可能偏深，这里用自定义浅红
            style.setFillForegroundColor(new XSSFColor(new java.awt.Color(255, 220, 220), new DefaultIndexedColorMap()));
        } else {
            // HSSF（xls）使用IndexedColors.ROSE（浅红）
            style.setFillForegroundColor(IndexedColors.ROSE.getIndex());
        }
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        return style;
    }

    /**
     * 根据表头名获取列索引（核心方法，确保准确）
     */
    private static int getColumnIndexByHeader(Row headerRow, String targetHeader) {
        // 遍历表头行的所有单元格，匹配表头名（忽略空格和大小写）
        for (Cell cell : headerRow) {
            if (cell == null) {
                continue;
            }
            String header = getCellValue(cell).trim();
            // 去除空格并忽略大小写比较（避免表头有空格导致匹配失败）
            if (header.replaceAll("\\s", "").equalsIgnoreCase(targetHeader.replaceAll("\\s", ""))) {
                return cell.getColumnIndex();
            }
        }
        // 未找到对应列
        return -1;
    }

    /**
     * 获取单元格值（处理各种类型）
     */
    private static String getCellValue(Cell cell) {
        if (cell == null) {
            return "";
        }
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    return String.valueOf(cell.getNumericCellValue());
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            default:
                return "";
        }
    }
}